﻿using System;
using System.Collections.Generic;
using System.Text;
using System.Configuration;
using System.IO;
using System.Net;
using System.Collections;
using System.Text.RegularExpressions;
using CDHunter.Manager;
using CDHunter.Util;

namespace CDHunter
{
    abstract class CheckBrand
    {
        private string _brandName;
        public string BrandName
        {
            get { return _brandName; }
            set { _brandName = value; }
        }

        private string _roductInfoTestOutPath;
        public string ProductInfoTestOutPath
        {
            get { return _roductInfoTestOutPath; }
            set { _roductInfoTestOutPath = value; }
        }

        private string _productRankTestOutPath;
        public string ProductRankTestOutPath
        {
            get { return _productRankTestOutPath; }
            set { _productRankTestOutPath = value; }
        }

        private string _volumeToken1;
        public string VolumeToken1
        {
            get { return _volumeToken1; }
            set { _volumeToken1 = value; }
        }

        private string _volumeToken2;
        public string VolumeToken2
        {
            get { return _volumeToken2; }
            set { _volumeToken2 = value; }
        }

        private int _volumeCount;
        public int VolumeCount
        {
            get { return _volumeCount; }
            set { _volumeCount = value; }
        }

        private string _strRegex;
        public string StrRegex
        {
            get { return _strRegex; }
            set { _strRegex = value; }
        }

        private Dictionary<string, string> _subCategoryURLDictionary = new Dictionary<string, string>();
        public Dictionary<string, string> SubCategoryURLDictionary
        {
            get { return _subCategoryURLDictionary; }
            set { _subCategoryURLDictionary = value; }
        }

        private List<SubCategoryInfo> _subCategoryInfoList = new List<SubCategoryInfo>();
        public List<SubCategoryInfo> SubCategoryInfoList
        {
            get { return _subCategoryInfoList; }
            set { _subCategoryInfoList = value; }
        }

        //CS02/CS07/NA
        private string _currentEnvironment;
        public string CurrentEnvironment
        {
            get { return _currentEnvironment; }
            set { _currentEnvironment = value; }
        }

        private Regex _productTitleRegex;
        public Regex ProductTitleRegex
        {
            get { return _productTitleRegex; }
            set { _productTitleRegex = value; }
        }

        private int _productTitleRegexGroupNum;
        public int ProductTitleRegexGroupNum
        {
            get { return _productTitleRegexGroupNum; }
            set { _productTitleRegexGroupNum = value; }
        }

        private Regex _productURIRegex;
        public Regex ProductURIRegex
        {
            get { return _productURIRegex; }
            set { _productURIRegex = value; }
        }

        private int _productURIRegexGroupNum;
        public int ProductURIRegexGroupNum
        {
            get { return _productURIRegexGroupNum; }
            set { _productURIRegexGroupNum = value; }
        }


        private Regex _productIDRegex;
        public Regex ProductIDRegex
        {
            get { return _productIDRegex; }
            set { _productIDRegex = value; }
        }

        private int _productIDRegexGroupNum;
        public int ProductIDRegexGroupNum
        {
            get { return _productIDRegexGroupNum; }
            set { _productIDRegexGroupNum = value; }
        }

        private bool _isDebugMode;
        public bool IsDebugMode
        {
            get { return _isDebugMode; }
            set { _isDebugMode = value; }
        }

        /// <summary>
        /// CheckBrand Constructor Function
        /// </summary>
        public CheckBrand()
        {
            //Set IsDebugMode Property in Constructor Function
            if (ConfigurationSettings.AppSettings["IsDebugMode"] == null)
            {
                IsDebugMode = true;
            }
            else if (ConfigurationSettings.AppSettings["IsDebugMode"].ToUpper().Equals("N") || ConfigurationSettings.AppSettings["IsDebugMode"].ToUpper().Equals("FALSE"))
            {
                IsDebugMode = false;
            }
            else
            {
                IsDebugMode = true;
            }
        }

        /// <summary>
        /// Download Page
        /// </summary>
        /// <param name="url"></param>
        /// <returns></returns>
        private String DownloadPage(Uri url)
        {
            WebRequest http = HttpWebRequest.Create(url);
            HttpWebResponse response = (HttpWebResponse)http.GetResponse();
            StreamReader stream = new StreamReader(response.GetResponseStream(), System.Text.Encoding.ASCII);

            String result = stream.ReadToEnd();

            response.Close();
            stream.Close();
            return result;
        }


        /// <summary>
        /// Generate Output Directory
        /// </summary>
        private void GenerateOptDirectory()
        {
            PathManager.GenerateDirectory(ProductInfoTestOutPath);
            PathManager.GenerateDirectory(ProductRankTestOutPath);
        }


        /// <summary>
        /// Set SubCategoryInfoList
        /// </summary>
        private void SetSubCategoryInfoList()
        {
            foreach (KeyValuePair<string, string> i in SubCategoryURLDictionary)
            {
                SubCategoryInfo scInfo = new SubCategoryInfo();
                scInfo.SubCategoryName = i.Key;
                scInfo.SubCategoryURI = new Uri(i.Value);

                SubCategoryInfoList.Add(scInfo);
            }

            //Get Current Environment (CS02/CS07/NA)
            if (SubCategoryInfoList != null && SubCategoryInfoList.Count > 0)
            {
                if (String.IsNullOrEmpty(CurrentEnvironment))
                {
                    CurrentEnvironment = ExtractManager.GetProductEnvironmentVersion(SubCategoryInfoList[0].SubCategoryURI, VolumeToken1, VolumeToken2, VolumeCount);
                }
            }

            Console.WriteLine("Current Environment: {0}", CurrentEnvironment);
        }

        /// <summary>
        /// Set ProductInfoList
        /// </summary>
        private void SetProductInfoList()
        {
            //LOOP PART 1
            foreach (SubCategoryInfo scInfo in SubCategoryInfoList)
            {
                Uri currentUri = scInfo.SubCategoryURI;

                //Fetch ProductURI
                WebRequest http = HttpWebRequest.Create(currentUri);
                HttpWebResponse response = (HttpWebResponse)http.GetResponse();
                StreamReader sr = new StreamReader(response.GetResponseStream(), System.Text.Encoding.ASCII);

                String inputString = sr.ReadToEnd();

                Regex myProductURIRegex = ProductURIRegex;
                if (myProductURIRegex.IsMatch(inputString))
                {
                    Match myMatch = myProductURIRegex.Match(inputString);
                    while (myMatch.Success)
                    {
                        ProductInfo pInfo = new ProductInfo();

                        string link = Regex.Replace(myMatch.Groups[ProductURIRegexGroupNum].Value.Replace("\r\n", " ").Trim(), @"( )\1+", "$1", RegexOptions.None);
                        if (IsDebugMode)
                        {
                            Console.WriteLine(link);
                        }
                        pInfo.ProductURI = new Uri(currentUri, link.Replace("&amp;", "&"));
                        scInfo.ProductInfoList.Add(pInfo);

                        myMatch = myMatch.NextMatch();
                    }
                }

                sr.Close();
                response.Close();
            }

            //LOOP PART 2
            foreach (SubCategoryInfo scInfo in SubCategoryInfoList)
            {
                foreach (ProductInfo pInfo in scInfo.ProductInfoList)
                {
                    //Fetch ProductID
                    String inputString1 = pInfo.ProductURI.ToString();

                    Regex myProductIDRegex = ProductIDRegex;
                    if (myProductIDRegex.IsMatch(inputString1))
                    {
                        Match myMatch = myProductIDRegex.Match(inputString1);
                        while (myMatch.Success)
                        {
                            string productID = Regex.Replace(myMatch.Groups[ProductIDRegexGroupNum].Value.Replace("\r\n", " ").Trim(), @"( )\1+", "$1", RegexOptions.None);
                            if (IsDebugMode)
                            {
                                Console.WriteLine(productID);
                            }
                            pInfo.ProductID = productID;

                            myMatch = myMatch.NextMatch();
                        }
                    }


                    //Fetch ProductTitle
                    WebRequest http = HttpWebRequest.Create(pInfo.ProductURI);
                    HttpWebResponse response = (HttpWebResponse)http.GetResponse();
                    StreamReader sr = new StreamReader(response.GetResponseStream(), System.Text.Encoding.ASCII);

                    String inputString2 = sr.ReadToEnd();

                    Regex myProductTitleRegex = ProductTitleRegex;
                    if (myProductTitleRegex.IsMatch(inputString2))
                    {
                        Match myMatch = myProductTitleRegex.Match(inputString2);
                        while (myMatch.Success)
                        {
                            string productTitle = Regex.Replace(myMatch.Groups[ProductTitleRegexGroupNum].Value.Replace("\r\n", " ").Trim(), @"( )\1+", "$1", RegexOptions.None);
                            if (IsDebugMode)
                            {
                                Console.WriteLine(productTitle);
                            }
                            pInfo.ProductTitle = productTitle;

                            myMatch = myMatch.NextMatch();
                        }
                    }
                    else
                    {
                        //No Match Found, may be caused by unactive product so lead to the error page. 
                        //We should remove it first, and add it to ErrorProductInfoList
                        pInfo.ProductTitle = "Inactive Product";

                        Console.WriteLine("Warning: This Product Info doesn't exists!");
                        Console.WriteLine("ProductID: {0}, ProductURL: {1}", pInfo.ProductID, pInfo.ProductURI.ToString());
                    }

                    sr.Close();
                    response.Close();
                }
            }
        }

        /// <summary>
        /// Output Unsorted ProductInfoList to XML
        /// </summary>
        private void OutputUnsortedProductInfoList()
        {
            string xmlFilePath;

            foreach (SubCategoryInfo scInfo in SubCategoryInfoList)
            {
                xmlFilePath = PathManager.GetXMLFilePath(ProductRankTestOutPath, scInfo.SubCategoryName + "_" + CurrentEnvironment);

                List<ProductInfo> sortedProductInfoList = scInfo.ProductInfoList;

                StreamWriter writer = new StreamWriter(xmlFilePath);
                writer.WriteLine(SerializerManager.Serialize<List<ProductInfo>>(sortedProductInfoList));
                writer.Close();
            }
        }


        /// <summary>
        /// Sort ProductInfo And Output Sorted ProductInfoList to XML
        /// </summary>
        private void SortAndOutputProductInfoList()
        {
            string xmlFilePath;

            foreach (SubCategoryInfo scInfo in SubCategoryInfoList)
            {
                xmlFilePath = PathManager.GetXMLFilePath(ProductInfoTestOutPath, scInfo.SubCategoryName + "_" + CurrentEnvironment);

                List<ProductInfo> sortedProductInfoList = scInfo.ProductInfoList;
                sortedProductInfoList.Sort(new ProductInfoComparision());

                StreamWriter writer = new StreamWriter(xmlFilePath);
                writer.WriteLine(SerializerManager.Serialize<List<ProductInfo>>(sortedProductInfoList));
                writer.Close();
            }
        }


        /// <summary>
        /// Execute Tasks
        /// </summary>
        public void ExecuteTasks()
        {
            //Task 1: If there is no such output directory, create it.
            GenerateOptDirectory();


            //Task 2: Set SubCategoryInfoList.
            SetSubCategoryInfoList();


            //Task 3: Loop Each SubCategoryInfo, Set ProductInfoList with ProductURI. And then Loop Eash ProductInfoList, then Set ProductInfoList
            SetProductInfoList();


            //Task 4: Output Unsorted ProductInfoList to XML.
            OutputUnsortedProductInfoList();


            //Task 5: Sort ProductInfo And Output Sorted ProductInfoList to XML.
            SortAndOutputProductInfoList();
        }
    }
}
